home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 24 / AACD 24.iso / AACD / Sound / LAME / WarpOS / src / dshow / Encoder.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-03-15  |  10.0 KB  |  348 lines

  1. /*
  2.  *    CEncoder wrapper for LAME
  3.  *
  4.  *    Copyright (c) 2000 Marie Orlova, Peter Gubanov, Elecard Ltd.
  5.  *
  6.  * This library is free software; you can redistribute it and/or
  7.  * modify it under the terms of the GNU Library General Public
  8.  * License as published by the Free Software Foundation; either
  9.  * version 2 of the License, or (at your option) any later version.
  10.  *
  11.  * This library is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.     See the GNU
  14.  * Library General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU Library General Public
  17.  * License along with this library; if not, write to the
  18.  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  19.  * Boston, MA 02111-1307, USA.
  20.  */
  21.  
  22. #include <streams.h>
  23. #include "Encoder.h"
  24.  
  25. DWORD dwBitRateValue[2][14] = {
  26.     {32,40,48,56,64,80,96,112,128,160,192,224,256,320},        // MPEG1 Layer 3
  27.     {8,16,24,32,40,48,56,64,80,96,112,128,144,160}            // MPEG2 Layer 3
  28. };
  29.  
  30. #define    SIZE_OF_SHORT 2
  31. #define MPEG_TIME_DIVISOR    90000
  32.  
  33. /////////////////////////////////////////////////////////////
  34. // MakePTS - converts DirectShow refrence time
  35. //             to MPEG time stamp format
  36. /////////////////////////////////////////////////////////////
  37. LONGLONG MakePTS(REFERENCE_TIME rt)
  38. {
  39.     return llMulDiv(CRefTime(rt).GetUnits(),MPEG_TIME_DIVISOR,UNITS,0);
  40. }
  41.  
  42. //////////////////////////////////////////////////////////////////////
  43. // Construction/Destruction
  44. //////////////////////////////////////////////////////////////////////
  45. CEncoder::CEncoder() :
  46.     m_bInpuTypeSet(FALSE),
  47.     m_bOutpuTypeSet(FALSE),
  48.     m_rtLast(0),
  49.     m_bLast(FALSE),
  50.     m_nCounter(0),
  51.     m_nPos(0),
  52.     m_pPos(NULL),
  53.     pgf(NULL)
  54. {
  55. }
  56.  
  57. CEncoder::~CEncoder()
  58. {
  59.     Close();
  60. }
  61.  
  62. //////////////////////////////////////////////////////////////////////
  63. // SetInputType - check if given input type is supported
  64. //////////////////////////////////////////////////////////////////////
  65. HRESULT CEncoder::SetInputType(LPWAVEFORMATEX lpwfex)
  66. {
  67.     CAutoLock l(this);
  68.  
  69.     if (lpwfex->wFormatTag            == WAVE_FORMAT_PCM) 
  70.     {
  71.          if (lpwfex->nChannels            == 1 || 
  72.             lpwfex->nChannels            == 2     ) 
  73.         {
  74.              if (lpwfex->nSamplesPerSec        == 48000 ||
  75.                 lpwfex->nSamplesPerSec        == 44100 ||
  76.                 lpwfex->nSamplesPerSec        == 32000 ||
  77.                 lpwfex->nSamplesPerSec        == 24000 ||
  78.                 lpwfex->nSamplesPerSec        == 22050 ||
  79.                 lpwfex->nSamplesPerSec        == 16000 ) 
  80.             {
  81.                 if (lpwfex->wBitsPerSample        == 16)
  82.                 {
  83.                     memcpy(&m_wfex, lpwfex, sizeof(WAVEFORMATEX));
  84.                     m_bInpuTypeSet = true;
  85.  
  86.                     return S_OK;
  87.                 }
  88.             }
  89.         }
  90.     }
  91.     m_bInpuTypeSet = false;
  92.     return E_INVALIDARG;
  93. }
  94.  
  95. //////////////////////////////////////////////////////////////////////
  96. // SetOutputType - try to initialize encoder with given output type
  97. //////////////////////////////////////////////////////////////////////
  98. HRESULT CEncoder::SetOutputType(MPEG_ENCODER_CONFIG &mabsi)
  99. {
  100.     CAutoLock l(this);
  101.  
  102.     m_mabsi = mabsi;
  103.     m_bOutpuTypeSet = true;
  104.     return S_OK;
  105. }
  106.  
  107. //////////////////////////////////////////////////////////////////////
  108. // SetDefaultOutputType - sets default MPEG audio properties according
  109. // to input type
  110. //////////////////////////////////////////////////////////////////////
  111. HRESULT CEncoder::SetDefaultOutputType(LPWAVEFORMATEX lpwfex)
  112. {
  113.     CAutoLock l(this);
  114.  
  115.     if(lpwfex->nChannels == 1)
  116.         m_mabsi.dwChMode = MONO;
  117.  
  118.     if((lpwfex->nSamplesPerSec < m_mabsi.dwSampleRate) || (lpwfex->nSamplesPerSec % m_mabsi.dwSampleRate != 0))
  119.         m_mabsi.dwSampleRate = lpwfex->nSamplesPerSec;
  120.  
  121.     return S_OK;
  122. }
  123.  
  124. //////////////////////////////////////////////////////////////////////
  125. // Init - initialized or reiniyialized encoder SDK with given input 
  126. // and output settings
  127. //////////////////////////////////////////////////////////////////////
  128. HRESULT CEncoder::Init()
  129. {
  130.     CAutoLock l(this);
  131.  
  132.     if(!pgf)
  133.     {
  134.         if (!m_bInpuTypeSet || !m_bOutpuTypeSet)
  135.             return E_UNEXPECTED;
  136.  
  137.         // Init Lame library
  138.         // note: newer, safer interface which doesn't 
  139.         // allow or require direct access to 'gf' struct is being written
  140.         // see the file 'API' included with LAME.
  141.         pgf = lame_init();
  142.  
  143.         pgf->num_channels = m_wfex.nChannels;
  144.         pgf->in_samplerate = m_wfex.nSamplesPerSec;
  145.         pgf->out_samplerate = m_mabsi.dwSampleRate;
  146.         pgf->brate = m_mabsi.dwBitrate;
  147.  
  148.         pgf->VBR = m_mabsi.vmVariable;
  149.         pgf->VBR_min_bitrate_kbps = m_mabsi.dwVariableMin;
  150.         pgf->VBR_max_bitrate_kbps = m_mabsi.dwVariableMax;
  151.  
  152.         pgf->copyright = m_mabsi.bCopyright;
  153.         pgf->original = m_mabsi.bOriginal;
  154.         pgf->error_protection = m_mabsi.bCRCProtect;
  155.  
  156.         pgf->no_short_blocks = m_mabsi.dwNoShortBlock;
  157.         pgf->bWriteVbrTag = m_mabsi.dwXingTag;
  158.         pgf->strict_ISO = m_mabsi.dwStrictISO;
  159.         pgf->VBR_hard_min = m_mabsi.dwEnforceVBRmin;
  160.         pgf->force_ms = m_mabsi.dwForceMS;
  161.         pgf->mode = m_mabsi.dwChMode;
  162.         pgf->mode_fixed = m_mabsi.dwModeFixed;
  163.  
  164.         if (m_mabsi.dwVoiceMode != 0)
  165.         {
  166.             pgf->lowpassfreq = 12000;
  167.             pgf->VBR_max_bitrate_kbps = 160;
  168.             pgf->no_short_blocks = 1;
  169.         }
  170.  
  171.         if (m_mabsi.dwKeepAllFreq != 0)
  172.         {
  173.             pgf->lowpassfreq = -1;
  174.             pgf->highpassfreq = -1;
  175.         }
  176.  
  177.         pgf->quality = m_mabsi.dwQuality;
  178.         pgf->VBR_q = m_mabsi.dwVBRq;
  179.  
  180.         lame_init_params(pgf);
  181.     }
  182.  
  183.     return S_OK;
  184. }
  185.  
  186. //////////////////////////////////////////////////////////////////////
  187. // Close - closes encoder
  188. //////////////////////////////////////////////////////////////////////
  189. HRESULT CEncoder::Close()
  190. {
  191.     CAutoLock l(this);
  192.  
  193.     if(pgf) {
  194.         lame_close(pgf);
  195.         pgf = NULL;
  196.     }
  197.     return S_OK;
  198. }
  199.  
  200. //////////////////////////////////////////////////////////////////////
  201. // Encode - encodes data placed on pSrc with size dwSrcSize and returns
  202. // encoded data in pDst pointer. REFERENCE_TIME rt is a DirectShow refrence
  203. // time which is being converted in MPEG PTS and placed in PES header.
  204. //////////////////////////////////////////////////////////////////////
  205. HRESULT CEncoder::Encode(LPVOID pSrc, DWORD dwSrcSize, LPVOID pDst, LPDWORD lpdwDstSize, REFERENCE_TIME rt)
  206. {
  207.     CAutoLock l(this);
  208.     BYTE temp_buffer[OUTPUT_BUFF_SIZE];
  209.  
  210.     *lpdwDstSize = 0;// If data are insufficient to be converted, return 0 in lpdwDstSize
  211.  
  212.     LPBYTE pData = temp_buffer;
  213.     LONG lData = OUTPUT_BUFF_SIZE;
  214.  
  215.     int nsamples = dwSrcSize/(m_wfex.wBitsPerSample*m_wfex.nChannels/8);
  216.  
  217.     if (pgf) {
  218.         lData = lame_encode_buffer_interleaved(pgf,(short*)pSrc,nsamples,pData,lData);
  219.  
  220.         if(m_mabsi.dwPES && lData > 0)
  221.         {
  222.             // Write PES header
  223.             Reset();
  224.             CreatePESHdr((LPBYTE)pDst, MakePTS(m_rtLast), lData);
  225.             pDst = (LPBYTE)pDst + 0x0e;            // add PES header size
  226.  
  227.             m_bLast = false;
  228.             m_rtLast = rt;
  229.         }
  230.         else
  231.             m_bLast = true;
  232.  
  233.         memcpy(pDst,pData,lData);
  234.         *lpdwDstSize = lData;
  235.     }
  236.     else {
  237.         *lpdwDstSize = 0;
  238.     }
  239.  
  240.  
  241.     return S_OK;
  242. }
  243.  
  244. //
  245. // Finsh - flush the buffered samples. REFERENCE_TIME rt is a DirectShow refrence
  246. // time which is being converted in MPEG PTS and placed in PES header.
  247. //
  248. HRESULT CEncoder::Finish(LPVOID pDst, LPDWORD lpdwDstSize)
  249. {
  250.     CAutoLock l(this);
  251.     BYTE temp_buffer[OUTPUT_BUFF_SIZE];
  252.  
  253.     *lpdwDstSize = 0;// If data are insufficient to be converted, return 0 in lpdwDstSize
  254.  
  255.     LPBYTE pData = temp_buffer;
  256.     LONG lData = OUTPUT_BUFF_SIZE;
  257.  
  258. #pragma message (REMIND("Finish encoding right!"))
  259.     if (pgf) {
  260.         lData = lame_encode_flush(pgf,pData,lData);
  261.  
  262.         if(m_mabsi.dwPES && lData > 0)
  263.         {
  264.             // Write PES header
  265.             Reset();
  266.             CreatePESHdr((LPBYTE)pDst, MakePTS(m_rtLast), lData);
  267.             pDst = (LPBYTE)pDst + 0x0e;            // add PES header size
  268.         }
  269.         m_bLast = true;
  270.  
  271.         memcpy(pDst,pData,lData);
  272.     }
  273.     else
  274.         lData = 0;
  275.  
  276.     *lpdwDstSize = lData;
  277.  
  278.     return S_OK;
  279. }
  280.  
  281. //////////////////////////////////////////////////////////////////////
  282. // PES headers routines
  283. //////////////////////////////////////////////////////////////////////
  284. // WriteBits - writes nVal in nBits bits on m_pPos address 
  285. //////////////////////////////////////////////////////////////////////
  286. void CEncoder::WriteBits(int nBits, int nVal)
  287. {
  288.     int nCounter = m_nCounter + nBits,
  289.         nPos = (m_nPos << nBits)|(nVal & (~( (~0L) << nBits)));
  290.     while(nCounter >= 8)
  291.     {
  292.         nCounter -= 8;
  293.         *m_pPos++ = (BYTE)(nPos >> nCounter) & 0xff;
  294.     }
  295.     m_nCounter = nCounter;
  296.     m_nPos = nPos;
  297. }
  298.  
  299. //////////////////////////////////////////////////////////////////////
  300. // CreatePESHdr - creates PES header on ppHdr address and writes PTS
  301. // and PES_packet_length fields
  302. //////////////////////////////////////////////////////////////////////
  303. void CEncoder::CreatePESHdr(LPBYTE ppHdr, LONGLONG dwPTS, int dwPacketSize)
  304. {
  305.     m_pPos = ppHdr;
  306.     WriteBits(24, 0x000001);    // PES header start code prefix 0x000001
  307.     WriteBits(8 , 0x0000c0);    //    stream_id 192?
  308.  
  309.     WriteBits(16, dwPacketSize + 0x000008);    //    PES_packet_length -- A 16 bit field specifying the number of bytes in the PES packet following the last byte of the field.
  310.  
  311.     WriteBits(2 , 0x000002);    //    marker
  312.     WriteBits(2 , 0x000000);    //    PES_scrambling_control --  The 2 bit PES_scrambling_control indicates the scrambling mode of the PES 
  313.  
  314.     WriteBits(1 , 0x000000);    //    PES_priority 
  315.     WriteBits(1 , 0x000000);    //    data_alignment_indicator When set to a value of '0' it is not defined whether any such alignment occurs or not.
  316.     WriteBits(1 , 0x000000);    //    copyright
  317.     WriteBits(1 , 0x000000);    //    original_or_copy
  318.  
  319.     WriteBits(2 , 0x000002);    //    PTS_DTS_flags -- A 2 bit flag. If the PTS_DTS_flags field equals '10', a PTS field is present in the PES packet header
  320.  
  321.     WriteBits(1 , 0x000000);    //    ESCR_flag
  322.     WriteBits(1 , 0x000000);    //    ES_rate_flag
  323.     WriteBits(1 , 0x000000);    //    DSM_trick_mode_flag
  324.     WriteBits(1 , 0x000000);    //    additional_copy_info_flag
  325.     WriteBits(1 , 0x000000);    //    PES_CRC_flag
  326.     WriteBits(1 , 0x000000);    //    PES_extension_flag
  327.  
  328.     WriteBits(8 , 0x000005);    //    PES_header_data_length = 5 bytes
  329.     // PTS
  330.     WriteBits(4 , 0x000002);    //    marker
  331.     WriteBits(3 , (int)(((dwPTS) >> 0x1f) & 0x07));    //    PTS [32.30]
  332.     WriteBits(1 , 0x000001);    //    marker
  333.     WriteBits(15 , (int)(((dwPTS) >> 0xf) & 0x7fff));    //    PTS [29.15]
  334.     WriteBits(1 , 0x000001);    //    marker
  335.     WriteBits(15 , (int)((dwPTS) & 0x7fff));    //    PTS [14.0]
  336.     WriteBits(1 , 0x000001);    //    marker
  337. }
  338.  
  339. //////////////////////////////////////////////////////////////////////
  340. // Reset - resets all PES header stuff
  341. //////////////////////////////////////////////////////////////////////
  342. void CEncoder::Reset()
  343. {
  344.     m_nCounter = 0;
  345.     m_nPos  = 0;
  346.     m_pPos = NULL;
  347. }
  348.